Navigating the files on your computer

An important part of using Python in the real world is to be able to examine the files you have on your computer!

Different operating systems (Windows, Mac, etc.) have different ways of organizing the files, so you will have to get familiar with the way things are organized on your own computer. The Python os module helps with that somewhat, so that we can use the same methods on different computers for doing what we want to do.


In [1]:
import os

print( os.listdir("/") )


['.com.apple.backupd.mvlist.plist', '.dbfseventsd', '.DocumentRevisions-V100', '.DS_Store', '.file', '.fseventsd', '.hotfiles.btree', '.PKInstallSandboxManager', '.Spotlight-V100', '.Trashes', '.vol', 'Applications', 'bin', 'cores', 'dev', 'Developer-old', 'etc', 'home', 'Incompatible Software', 'installer.failurerequests', 'Library', 'net', 'Network', 'opt', 'private', 'sbin', 'System', 'tmp', 'User Guides And Information', 'User Information', 'Users', 'usr', 'var', 'Volumes']

The files in our system are on one or more drives; on the drive the files are organized into folders, also known as directories. We can list the contents of any directory by using the os.listdir() method.

The / has a special meaning in most cases: it is the character that divides directory names. So a / by itself means "the root directory of the drive: what I get if I look at C: on Windows or Macintosh HD on the Mac."

So, here we have listed the contents of that root directory (which is a lot more than you'll see in your Explorer or Finder window - all the names starting with '.' and even the ones that are all-lowercase are hidden, if you're on a Mac.)

We can also list the contents of any other directory. For example, the Downloads folder on my Mac is in the folder with my short name (tla), which is in a folder called Users, which is right on the Macintosh HD. So I say

/Users/tla/Downloads

to get at it. That is: Starting at the root (/), look in Users; starting at Users (/Users/), look in tla; starting at tla (/Users/tla/), look in Downloads.

If you are on Windows you will probably want something like /Users/Tara Andrews/Downloads instead.

Let's print out each of the filenames we find in that directory.


In [2]:
for f in os.listdir("/Users/tla/Downloads"):
    print(f)


.DS_Store
.localized
10.1.1.155.1251.pdf
10.1.1.172.6041.pdf
110728_1900_Zurich Triathlon 5i50.pdf
156128_Andrews.docx.pdf
2013 April 10 Tara Andrews.docx
2014-archiv -gesamtrangliste .pdf
2014-archiv-rangliste-laeufe.pdf
20140402_AdminPart_Checked_English.pdf
30708.pdf
3224387_p.jpg
3rd-AGE_MIDDLE-EARTH map_v2.jpg
440-893-1-PB.pdf
4_Hoflichkeit_Anstand_Benehmen.docx
4A-DH101-slides.pptx
5277532167_49079b93c8_b.jpg
5_offline_Leben_ohne_Internet.pdf
626463131.fit
626463136.fit
6730021199_6b43ca7eb0_o.jpg
682010751.fit
About Downloads.pdf
activity_576077791.tcx
activity_664654016.tcx
alegreya
Anaconda3-2.1.0-MacOSX-x86_64.pkg
Andrews-book_intro-BM-05April13.pdf
Archive.zip
AuthWP.php
BAG_ImpfBrosch_D.pdf
Belegungsplan_Oerlikon_Schwimmerbecken.pdf
Bibliotheken
Bibliotheken.zip
bill_11424293_9900177321102013.pdf
bill_11424293_9900721509112013.pdf
bill_voice_11424293.csv
bodleian_arches.psd
bodleian_arches_small.jpg
brill_italic_1.00_021.otf
brill_roman_1.00_021.otf
busa_techs.jpg
byzcoins.pdf
commentary corrected.xls
COST.pdf
Coulie_Kindt_Pataridze.pdf
Die_verschiedenen_Minister.pdf
dietikon20150114.pdf
Digital_Humanities_2013_Registrationform.rtf
DivXInstaller.dmg
download.png
DSC05183.JPG
EAH_Submissions_Guidelines.pdf
ECOST_Rules_for_Travel_Reimbursement_Request.pdf
EMC vol 1.pdf
EMC vol 2.pdf
Enrolment Waiting List.doc
ERC-PMR-B1.doc
erika.json
europe_map.png
europe_map.svg
Eva Tara Andrews.pdf
fitbit_export_20121109.xls
FitbitConnect_Mac_20130226_1.0.0.2575.dmg
FitSDKRelease_7
Flip4Mac 3.1.0.24.dmg
FORM.xls
fqq007v1.pdf
ganttproject-2.7-r1891.dmg
GarminExpressInstaller.dmg
googleearth-chrome-bundle-intel.dmg
Greenwood03.docx
Grosse_Schanze_Bern_03_10.jpg
Guidelines_research_plan.pdf
hackdiet
Horsefly Farm.html
horsefly_access_files
HTML5 Boilerplate.zip
Hungry baby.jpg
IMAG0304.jpg
images.jpeg
img06872.pdf
IMG_0806.JPG
IMG_1185.MOV
imgres.html
in-novam_export.xml
joinspbs.rtf
Journal 1937 of Grace Craig Hazard.pdf
junicode-0-7-2.zip
khorenatsi.rar.html
Kittler, Gramophone, Film, Typewriter, p. xi-19.pdf
LATE ANTIQUE AND EARLY  May2014.doc
Lectio1_Romanov.pdf
Leuven2-3April12.xlsx
LocalSettings.php
Machiavelli_and_the_art_of_Renaissance_h.bibtex
MacPorts-2.3.3-10.10-Yosemite.pkg
Manuscript_Andrews_monograph.pdf
marlin_tibtec20_358.ris
matthew_part1.png
mclc05.ppt
Mittelbau-2014.pdf
Mother and daughter.jpg
MOTHER-RUNNER-SURVEY-A-J.doc
mpk-cpermit.pdf
NFFBAR.pdf
OldDog.jpg
On-ExploreTheCity-Paris-10km.pdf
On-ExploreTheCity-Paris-5km.pdf
online_communities.png
online_communities_2_large.png
oxygen.zip
p-066-2.pdf
p-066.pdf
P1010505.RW2
P9086034.JPG
P9086035.JPG
P9086036.JPG
P9086037.JPG
P9086039.JPG
P9086040.JPG
P9086041.JPG
P9086042.JPG
P9086043.JPG
P9086044.JPG
papers_2112.dmg
papers_264.dmg
Parcel Monkey.webarchive
Parzival 235.xml
path2105.png
Patrologiae_cursus_completus.pdf
peevalues.R
pi020.JPG
Pipes Cthulhu.mp3
PostFinance
process.xsl
pubs_wordcloud.png
race-1-2011-public-final.xls
race-4-final-public.xls
Reading List.docx
RegistrationForm_Eng..doc
result_graph.xml
Rubicon Application form April 2010.doc
S000000060CL04.C2C20100325154451.docx
S000000060CONR.C1D20100317144105.docx
SamenvattingPromotieJZ.doc
Sceptical Tara.jpg
SDSE_2013.docx
SESA_Guidelines.pdf
set01_tsfw.zip
set02_ALL.zip
sextum_psalmum_II.xml
Situationsplan_Seebad_Utoquai.pdf
Souscription Mélanges Mahé-signed.pdf
Souscription Mélanges Mahé.pdf
stemmatology.tar.gz
stemmatree.png
stemmatree.svg
stylesheets
synology-cloud-station-3320.dmg
TDPguidelines.pdf
testocr.docx
TLA UK Passport.pdf
tla_GS353816051805820-1415898502000.tcx
understanding_dh.jpg
unibern_logo.gif
Verbum uncorrected CollateX 
verbum_collatex.xlsx
VIDEO0030_01.mp4
Virgin Active London Triathlon 2013 - Olympic.xls
WarenkorbDruckansicht.pdf
Week 7- Presentation - Felicia & Sanya.pdf
Workshop-Rome-2013-participants.xlsx

Now open a Finder window, or an Explorer window, and see how the name here corresponds to the structure of the directories on your drive. This is the filesystem.

In Python (or in any program running on your computer for that matter) it always runs from somewhere in this filesystem - some specific directory on your drive. To see where you are running now, you can ask for the current working directory, like so:


In [3]:
print(os.getcwd())


/Users/tla/Projects/Tools-and-Techniques/lessons

This will look a little different on Mac vs. Windows, because they use different notations (called the path) for their directory structure.

C:\Users\Tara L Andrews\Documents\IPython Notebooks

vs.

/Users/tla/Documents/2014 FS

So you'll need to get used to the convention on whichever sort of computer you have. The / (or \, as the case may be) is called the path separator, separating the chain of directories.

The two important lessons to take from this are:

  • If you are not sure where you are, then os.getcwd() will tell you.
  • If you value your sanity, don't use / or \ when you name your folders and files.

Once you know where you are on the filesystem, you can go somewhere else by "changing directory". This is accomplished with the os.chdir() method. For example:


In [4]:
os.chdir("/Users/tla")   # go to the directory tla in the directory Users at the base of the drive
os.chdir("..")           # go one directory down
print(os.getcwd())       # see where we are

os.chdir("./tla/Downloads")  # go to the directory Downloads in the directory tla that is here where we are
print(os.getcwd())           # see where we are now


/Users
/Users/tla/Downloads

There are a few special names when you look at files and directories:

.  - the directory I'm standing in
.. - the directory that holds the directory I'm standing in
/  - (all by itself) the base ("root") directory

The / is a little more complicated than that if you are on Windows; really there you should be using \ instead of /, but Python lets you call it / anyway. Moreover, it is the base directory of the drive you are currently looking at (e.g. C:, D:, or whatever.) Macs don't deal with drives in the same way, so if you are on a Mac then you can ignore all this.

So by saying

os.chdir("..")

we have moved down a directory. We could keep doing this all the way to the bottom, if we felt like it. But generally it is a good idea to stay in your home directory if you can.

Wait, what is a home directory?


In [5]:
print(os.getenv("HOME", "not Mac/Unix"))
print(os.getenv("HOMEPATH", "not Windows" )) # alternatively, USERPROFILE


/Users/tla
not Windows

If you're on a Mac, this is the directory that has the little icon of a house in the Finder. It is where all of the files you work with ought to be stored, and normally has your Documents folder and Downloads folder and all of that.


In [6]:
my_home = os.getenv("HOME")
for f in os.listdir( my_home ):
    print(f)


.adobe
.anyone
.appcfg_nag
.astropy
.bash_history
.bash_profile
.bash_profile-anaconda.bak
.bash_profile.macports-saved_2010-04-21_at_20:42:56
.bash_profile.macports-saved_2014-03-06_at_23:21:07
.bash_profile.macports-saved_2015-02-27_at_19:18:17
.bashrc
.cache
.CFUserTextEncoding
.CloudStation
.config
.continuum
.cpan
.cpanm
.crypt-table
.cups
.cvspass
.distlib
.dropbox
.DS_Store
.eclipse
.emacs
.emacs.d
.enthought
.et.index.imapmbox
.fontconfig
.fonts.cache-1
.ganttproject
.gconf
.gconfd
.gdb_history
.gem
.gervill
.gitconfig
.gnome
.gnome2
.gnome_private
.gnucash
.gnupg
.gpg-agent-info
.inkscape-etc
.ipynb_checkpoints
.ipython
.irssi
.java
.jpi_cache
.k
.lesshst
.links
.m2
.macports
.mailboxlist.imapmbox
.matplotlib
.mboxCache.plist
.muttrc
.muttrc.imap
.muttrc.u0
.mysql_history
.ncftp
.netbeans-derby
.owl
.owlconf
.owlconf~
.pip
.pyxbld
.Rapp.history
.realobjects
.rnd
.spyder2
.sqlite_history
.ssh
.subversion
.Synology
.texmf-old-var
.texmf-var
.Trash
.vim
.viminfo
.vpn
.Xauthority
.xchat2
.Xcode
.xdvirc
.xftcache
.xinitrc.old
.zephyr.subs
.zephyr.subs.backup
.zephyr.vars
.zwgc.desc
01_foundation.pdf
060901tips.txt
201210220747116179300.pdf
248911317.csv
250913623.csv
aa.csv
abstract.txt
ac.csv
addr
anaconda
analysis_all.csv
analysis_combi.csv
anatk
Aperture.dmg
Applications
aristakes_trans.txt
arm_translated.txt
athens.txt
August pack letter 06.doc
baden.jpg
bb1.txt
bbedit.about
bin
bookmoney.txt
brainquiz
buf
cacert-pem.crt
catalogues.txt
CFP_edit.txt
ch
ch1
chiractalk.txt
clean_csv.pl
CloudStation
comm
convert_address.pl~
De_duabus.pdf
Desktop
dhch.numbers
DocLocal
docstrip.log
Documents
DocVC
Downloads
Dropbox
duabus_phylo.pdf
duabus_phylo_ac.pdf
earnings
ednew.txt
edold.txt
en_library.txt
englishversion1.doc
erika.json
espp.txt
essay
exp
file
file.txt
files.txt
fit_test.csv
fit_test_data.csv
flickrimport
fonts
fwo_krr_notes.txt
ganttproject.log
garmin.csv
git
gitusers
GNUstep
goulash.txt
guestnight.txt
heart
Helpdesk.tgz
hennessy_childbride.pdf
history_chap.txt
horsefly
horsefly.tgz
huhyphn.tex
icon.jpg
id_dsa.pub
identity.pub
images
in-novam_export_with-A2.xml
index.html
inserts.doc
inserts.pdf
inst.txt
interedition.log
interedition_may2012
invites.csv
irc.window8.log.txt
iWork08Trial.dmg
java0.log
john.svg
journal
journal.txt
jrv.chat
json
lemmatizer
lent
Library
list.txt
livanios_choniates.pdf
lmhnotes
logts.pl
lshort.pdf
lyricfree.txt
Mail
merge_ac.pl
MobileLJ
move.pl
Movies
Music
music.tar
name_reaction.txt
names_all.txt
NetBeansProjects
newyork
nltk_data
nocc
nodes.dot
nodes.jpg
nodes.svg
notes
OBS_hilary_program.pdf
obs_maillist.txt
obs_maillist_old.txt
obs_record
oldmail
order.pl
pace6x500.tiff
Palm software
parzival_new.xml
pbw.hours
pbw_all.sql
pdbackup
pic.out
Pictures
Pilgrimage
PO_Yahya.pdf
portlist
Projects
Public
RB issues
replpics.pl
replpics.pl~
reply
request.json
request.post
research_outline.txt
resp.json
result.html
resume.html
Rheinfall
rmcookies
roll1
roll2
rsvp.txt
scrapegraph.py
scratch
section
shares.txt
Sites
Software
spec.txt
sphakia.tgz
src
status
stellamaris.txt
style.css
styles-site.css
styling.tiff
sunset.jpg
svn
svn-commit.tmp
sylfaen.ttf
t.pl
t5rebate.jpg
t5rebate.pdf
tara_andrews.xml
tara_andrews_cv.doc
tara_andrews_cv.pdf
taxinfo2001.txt
taxreturn2003.pdf
term
test.csv
test.svg
textual_communties.docx
Thesis
thpage.pdf
tmp1.txt
traditions.db
translation_wotd
transp1.jpg
transp1.svg
transp2.svg
transp2.tiff
trips.txt
trips.txt~
uffish.txt~
uffish_june.txt
unadventurous.txt
univpics
UpIntDeutsch.txt
ur5k.fit
url.sty
v887_excerpt.xml
verbum_collatex.xls
verbum_collatex.xlsx
Volumes
weatherParser.js
weblog
well_links.txt
weston
Work
zlog

Now, if I want to, I can look to see what we have in my Projects folder - this is where I usually keep the code I've worked on. I can do this by joining the directory name ('Projects') to my home directory (which I've saved in my_home.)


In [17]:
doc_path = os.path.join( my_home, "Projects" )
print( "The join operationdoc_path )
os.listdir( doc_path )


/Users/tla/Projects
Out[17]:
['.DS_Store',
 'armenian_lemmatizer',
 'Armenmorph',
 'Battleship',
 'BeatBox',
 'bootstrap-3.2.0-dist.zip',
 'BoredNow.1.0.C014',
 'bps',
 'C',
 'cdecl',
 'Chronicle',
 'cocoa_notes.txt',
 'collatex',
 'collatex-tools-1.5',
 'collatex-tools-1.5.zip',
 'collatexInstallation',
 'cpanmods',
 'cx_ui',
 'db-4.4.16',
 'DBIx-SearchBuilder',
 'digitaldata_2015',
 'Email-Auth-AddressHash-1.0',
 'erika',
 'flashpdb_convert',
 'HeadFirst',
 'hoenen',
 'idp-source.tar.gz',
 'Info.plist',
 'infogrid',
 'ipython_nose',
 'irssi-0.8.15',
 'irssi-0.8.15.tar.gz',
 'JPype-0.5.4.2',
 'la.po',
 'mmslj',
 'morphology',
 'MyFirstStep',
 'ncritic',
 'opensocial.tar',
 'PBW',
 'phylip-3.69',
 'pl.po.txt',
 'prosopography',
 'puppet',
 'python-embedded',
 'rfc2445.txt',
 'rt',
 'scomp',
 'scomp.zip',
 'scratch',
 'sphakia',
 'stemmatology',
 'stemmaweb',
 'TEITokenizer',
 'tlaide',
 'Tools-and-Techniques',
 'TreeTagger',
 'trinity',
 'ui-demos']

If we are sure we know where we are, and that the folder we want to see is in the same directory we are in, then we don't have to do the path joining after all.


In [15]:
os.chdir( my_home )            # Change to my home directory
os.listdir( "Dropbox/book" )   # Look at the 'book' folder in the Dropbox folder in my home directory


Out[15]:
['.DS_Store',
 '2013 April 10 Tara Andrews.docx',
 'Andrews-book_intro-BM-05April13.pdf',
 'appendices.aux',
 'appendices.tex',
 'armenia_map105.pdf',
 'armenia_map108.pdf',
 'armenia_map119.pdf',
 'armenia_map87.pdf',
 'book_main.aux',
 'book_main.bbl',
 'book_main.bcf',
 'book_main.bib',
 'book_main.blg',
 'book_main.log',
 'book_main.pdf',
 'book_main.run.xml',
 'book_main.tex',
 'book_main.toc',
 'book_main_bib.pdf',
 'byzantium.aux',
 'byzantium.tex',
 'chronicletext.tex',
 'conclusion.aux',
 'conclusion.tex',
 'ecclesiastes.aux',
 'ecclesiastes.tex',
 'frontmatter.aux',
 'frontmatter.tex',
 'hayastan.aux',
 'hayastan.tex',
 'introduction.aux',
 'introduction.tex',
 'manuscripts.aux',
 'manuscripts.tex',
 'prophecy.aux',
 'prophecy.tex',
 'translation.aux',
 'translation.tex',
 'turks.aux',
 'turks.tex']

Reading files

Now that we know how to navigate around our directory, we might also want to look inside some files! Here's how we do that.


In [9]:
fh = open( os.path.join( my_home, "Dropbox/beef_stew.txt" ), 'r' )   # Open the file
contents = fh.read()                        # Read its contents
fh.close()                                  # Close the file
print(contents)                             # Do something with the contents


500 grams of beef
heat a mixture of about 30 grams of butter and three table spoons of olive oil
put in the meat, fry brownish on all sides
keep turning
add plenty of pepper, salt, coriander, rosemary, nutmeg
add a glass of white wine
add a cube of dried beef broth 
add a glass of water
(the meat should almost be under the moisture, but not completely)
add two bay leaves
add just short of a tablespoon of normal mustard
same for brown sugar
Turn the heat down as far as possible, ideally 99 degrees but err on the low side
now sit back for at least three hours
if there's too much moisture left, simple heat up and cook it away until you are 
  left with a nice almost sauce like gravy
enjoy

There are three steps to dealing with files from Python:

  1. Open it
  2. Read (or write) whatever you need
  3. Close it

When you open a file, you make something called a filehandle. The filehandle, well, handles the file - does the reading, writing, closing, etc. that you need to be done.

When you read a file, you have two choices: read in the entire thing, or read it line-by-line. Usually you'll choose to do the latter, so that you can process or analyze each line as you get it. So, for example, we could add line numbers to what is in this file.

Pay attention though: every line in the file ends with a line break. The print function adds a newline (a technical term for that line break) after everything it prints, by default. Since the lines in the file already have a newline, if we are not careful we will also be double-spacing the file! In order to avoid that, we end the print statement with this parameter

end=""

which says "Instead of the newline you would normally print at the end, print nothing instead."


In [10]:
fh = open( "Dropbox/beef_stew.txt" )
counter = 1
for line in fh:
    print("%d: %s" % ( counter, line ), end="")
    counter += 1
fh.close()


1: 500 grams of beef
2: heat a mixture of about 30 grams of butter and three table spoons of olive oil
3: put in the meat, fry brownish on all sides
4: keep turning
5: add plenty of pepper, salt, coriander, rosemary, nutmeg
6: add a glass of white wine
7: add a cube of dried beef broth 
8: add a glass of water
9: (the meat should almost be under the moisture, but not completely)
10: add two bay leaves
11: add just short of a tablespoon of normal mustard
12: same for brown sugar
13: Turn the heat down as far as possible, ideally 99 degrees but err on the low side
14: now sit back for at least three hours
15: if there's too much moisture left, simple heat up and cook it away until you are 
16:   left with a nice almost sauce like gravy
17: enjoy

Writing to files

When we open a file, we can either be reading from it or writing to it (but not both, at least not at this stage.)

When we write to a file that already exists, there are two options: either we will replace whatever was there before, or we will add to it. Let's try it, first to a new file and then adding something to that file.

When we use the open() function, it takes two parameters: the filename and a letter that indicates whether we want to read or write or what. If we don't give any letter, it assumes we meant 'r' for 'read'. The options are:

  • r - open the file to reading
  • w - empty the file and open it to writing
  • a - open the file for writing (appending) to the end; do NOT empty it.

We can see this in action, by opening the old recipe for reading and a new recipe for writing. Where we use .read() on the old file, we will use .write() on the new file.

The write function is a lot like print, only it does NOT assume that you want a carriage return at the end. In this case that is pretty convenient, since we don't!


In [11]:
old_recipe = open( "Dropbox/beef_stew.txt" )
new_recipe = open( "Dropbox/numbered_beef_stew.txt", "w" )
counter = 1
for line in old_recipe:
    new_recipe.write( "%d: %s" % ( counter, line ) )
    counter += 1  # this is the same as counter = counter + 1
old_recipe.close()
new_recipe.close()

So let's look at the new recipe! We open it for reading this time, instead of writing.


In [12]:
new_recipe = open( "Dropbox/numbered_beef_stew.txt" )
contents = new_recipe.read()
new_recipe.close()

print(contents)


1: 500 grams of beef
2: heat a mixture of about 30 grams of butter and three table spoons of olive oil
3: put in the meat, fry brownish on all sides
4: keep turning
5: add plenty of pepper, salt, coriander, rosemary, nutmeg
6: add a glass of white wine
7: add a cube of dried beef broth 
8: add a glass of water
9: (the meat should almost be under the moisture, but not completely)
10: add two bay leaves
11: add just short of a tablespoon of normal mustard
12: same for brown sugar
13: Turn the heat down as far as possible, ideally 99 degrees but err on the low side
14: now sit back for at least three hours
15: if there's too much moisture left, simple heat up and cook it away until you are 
16:   left with a nice almost sauce like gravy
17: enjoy

Let's say we forgot a step at the end, and want to add it.

When we write a new line to the file, since we are using .write() and not print(), we have to make sure to add the carriage return at the end of the line. In Python this can usually be done with the term "\n".

Finally, although it is always important to close the files we open, it is especially important if we are writing to the file. If we forget to close a file we're writing to, then it's possible that not everything will get written!


In [13]:
new_recipe = open( "Dropbox/numbered_beef_stew.txt", "a" )
new_recipe.write( "18: give the leftovers to the cat\n" )
new_recipe.close()

And let's see if that worked. This time, instead of using .read() to put the file into a single variable, we will use .readlines() to put the file line by line into an array. This is useful if you want to read the file all in one go, but are going to want to do something with its contents line by line.


In [14]:
new_recipe = open( "Dropbox/numbered_beef_stew.txt" )
contents = new_recipe.readlines()
new_recipe.close()

for line in contents:
    print("-", line, end='')


- 1: 500 grams of beef
- 2: heat a mixture of about 30 grams of butter and three table spoons of olive oil
- 3: put in the meat, fry brownish on all sides
- 4: keep turning
- 5: add plenty of pepper, salt, coriander, rosemary, nutmeg
- 6: add a glass of white wine
- 7: add a cube of dried beef broth 
- 8: add a glass of water
- 9: (the meat should almost be under the moisture, but not completely)
- 10: add two bay leaves
- 11: add just short of a tablespoon of normal mustard
- 12: same for brown sugar
- 13: Turn the heat down as far as possible, ideally 99 degrees but err on the low side
- 14: now sit back for at least three hours
- 15: if there's too much moisture left, simple heat up and cook it away until you are 
- 16:   left with a nice almost sauce like gravy
- 17: enjoy
- 18: give the leftovers to the cat

You can open and close a file as often as you need to in the same program, as long as you always close it before reopening it somewhere else!

Once you know your way around the files and directories on your system, a lot of things start to make a lot more sense...

  • Spyder and its default temporary script
  • Saving and running a Python program
  • Making a CSV file out of some geographic data you have, and saving it somewhere for import to Google Maps